﻿using System;
using System.Linq;
using System.Text;
using DevExpress.Xpo;
using DevExpress.ExpressApp;
using System.ComponentModel;
using DevExpress.ExpressApp.DC;
using DevExpress.Data.Filtering;
using DevExpress.Persistent.Base;
using System.Collections.Generic;
using DevExpress.ExpressApp.Model;
using DevExpress.Persistent.BaseImpl;
using DevExpress.Persistent.Validation;
using DevExpress.Xpo.Metadata;

namespace aztall.Module.BusinessObjects
{
	[RuleCriteria("StartDateRange", DefaultContexts.Save, "Promo.StartDate <= FromDate && Promo.EndDate >= FromDate", ResultType = ValidationResultType.Warning, CustomMessageTemplate = "Promo Vol: From Date is out of Promotion Start Date / End Date")]
	[RuleCriteria("EndDateRange", DefaultContexts.Save, "Promo.StartDate <= ToDate && Promo.EndDate >= ToDate", ResultType = ValidationResultType.Warning, CustomMessageTemplate = "Promo Vol: To Date is out of Promotion Start Date / End Date")]
	[RuleCriteria("StartDate<=ToDate", DefaultContexts.Save, "FromDate <= ToDate", ResultType = ValidationResultType.Error, CustomMessageTemplate = "Promo Vol: To Date should not be earlier than Start Date")]
	[ImageName("BO_Order_Item")]
	public class PromoVol : DomainObject
	{
		protected Customer _Customer;
		protected Sku _Sku;
		protected DateTime _FromDate;
		protected DateTime _ToDate;
		protected double _Uplift;
		protected double _PPD;
		protected double _CANN;

		public PromoVol(Session session)
				: base(session)
		{
		}
		public override void AfterConstruction()
		{
			base.AfterConstruction();
		}
		protected override void OnSaving()
		{
			if (!this.IsDeleted)
			{
				var vs = Promo.PromoVols.Where(c => (c.InstanceId != this.InstanceId) && c.Customer.Oid == Customer.Oid && c.Sku.Oid == Sku.Oid && c.FromDate <= ToDate && c.ToDate >= FromDate).ToList();

				//delete fully wrap records
				var v1 = vs.Where(t => t.FromDate >= this.FromDate && t.ToDate <= this.ToDate).ToList();
				base.Session.Delete(v1);

				//trim FromDate/ToDate of existing records
				var v2 = vs.Where(t => (t.FromDate >= this.FromDate && t.FromDate <= this.ToDate && t.ToDate > this.ToDate) ||
															 (t.ToDate >= this.FromDate && t.ToDate <= this.ToDate && t.FromDate < this.FromDate)
														);
				foreach (PromoVol t in v2)
				{
					if (t.ToDate > this.ToDate)
						t.FromDate = this.ToDate.AddDays(1);
					else
						t.ToDate = this.FromDate.AddDays(-1);
				}
				// split records
				var v3 = vs.Where(t => t.FromDate < this.FromDate && t.ToDate > this.ToDate);
				PromoVol R;
				foreach (PromoVol L in v3)
				{
					R = new PromoVol(this.Session) { Domain = this.Session.FindObject<Domain>(new BinaryOperator("Oid", L.Domain.Oid)), Promo = L.Promo, Customer = L.Customer, Sku = L.Sku, FromDate = this.ToDate.AddDays(1), ToDate = L.ToDate, Uplift = L.Uplift, CANN = L.CANN, PPD = L.PPD };
					L.ToDate = this.FromDate.AddDays(-1);
				}
			}
			base.OnSaving();
		}
		private Promo _Promo;
		[Association("Promo_PromoVols", UseAssociationNameAsIntermediateTableName = true), XafDisplayName("Promotion")]
		public Promo Promo
		{
			get { return _Promo; }
			set { SetPropertyValue<Promo>(nameof(Promo), ref _Promo, value); }
		}
		#region Properties
		[DataSourceProperty("Promo.Customers"), RuleRequiredField(DefaultContexts.Save, SkipNullOrEmptyValues = false)]
		public Customer Customer
		{
			get { return _Customer; }
			set
			{
				if (SetPropertyValue(nameof(Customer), ref _Customer, value) && _Promo != null && !IsLoading)
					_Promo.UpdatePromoCosts(true);
			}
		}
		[DataSourceProperty("Promo.Skus"), RuleRequiredField(DefaultContexts.Save, SkipNullOrEmptyValues = false)]
		public Sku Sku
		{
			get { return _Sku; }
			set
			{
				if (SetPropertyValue(nameof(Sku), ref _Sku, value) && _Promo != null && !IsLoading)
					_Promo.UpdatePromoCosts(true);
			}
		}
		[RuleRequiredField(DefaultContexts.Save, SkipNullOrEmptyValues = false)]
		public DateTime FromDate
		{
			get { return _FromDate; }
			set
			{
				if (SetPropertyValue(nameof(FromDate), ref _FromDate, value) && _Promo != null && !IsLoading)
					_Promo.UpdatePromoCosts(true);
			}
		}
		[RuleRequiredField(DefaultContexts.Save, SkipNullOrEmptyValues = false)]
		public DateTime ToDate
		{
			get { return _ToDate; }
			set
			{
				if (SetPropertyValue(nameof(ToDate), ref _ToDate, value) && _Promo != null && !IsLoading)
					_Promo.UpdatePromoCosts(true);
			}
		}
		public int Days
		{
			get { return (int)(ToDate - FromDate).TotalDays + 1; }
		}
		[RuleRange("Uplift >= 0", DefaultContexts.Save, 0, int.MaxValue, ResultType = ValidationResultType.Warning, CustomMessageTemplate = "Uplift should be a positive number.")]
		[XafDisplayName("Uplift per Day")]
		public double Uplift
		{
			get { return _Uplift; }
			set
			{
				if (SetPropertyValue(nameof(Uplift), ref _Uplift, value) && _Promo != null && !IsLoading)
					_Promo.UpdatePromoCosts(true);
			}
		}
		[RuleRange("PPD <= 0", DefaultContexts.Save, int.MinValue, 0, ResultType = ValidationResultType.Warning, CustomMessageTemplate = "PPD should be a negative number.")]
		[XafDisplayName("PPD per Day")]
		public double PPD
		{
			get { return _PPD; }
			set
			{
				if (SetPropertyValue(nameof(PPD), ref _PPD, value) && _Promo != null && !IsLoading)
					_Promo.UpdatePromoCosts(true);

			}
		}
		[RuleRange("CANN <= 0", DefaultContexts.Save, int.MinValue, 0, ResultType = ValidationResultType.Warning, CustomMessageTemplate = "CANN should be a negative number.")]
		[XafDisplayName("Cann per Day")]
		public double CANN
		{
			get { return _CANN; }
			set
			{
				if (SetPropertyValue(nameof(CANN), ref _CANN, value) && _Promo != null && !IsLoading)
					_Promo.UpdatePromoCosts(true);
			}
		}
		#endregion
	}
}
